﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CrmContacto.Contracts;
using CrmContacto.Data;
using Web.Framework.Svc;
using System.Net.Mail;
using System.IO;
using CrmContacto.Contracts.Enums;
using Web.Framework.Translate;
using System.Transactions;
using CrmContacto.Services.Classes;
using System.Configuration;
using CrmContacto.Services.Common;
using System.Threading;
using CrmContacto.Services.Marketing.Promociones;
using CrmContacto.Contracts.Contracts.Search;
using CrmContacto.Contracts.Promociones;
using CrmContacto.Contracts.Contracts;
using Web.Framework.Helpers;

namespace CrmContacto.Services.Marketing
{
    public class PromocionesDeUso : PromocionStrategyBase, IPromocionStrategy
    {
        public int EmpresaId { get; set; }
        public virtual string Nombre
        {
            get { return "PromocionesDeUso"; }
        }

        public PromocionResultado CrearPromocion(PtoVentaRegistroCliente customer, bool esNuevo)
        {
            PromocionResultado promocionResultado = new PromocionResultado();
            promocionResultado.ContinuarProcesando = true;
            promocionResultado.EnviarEmailDeBienvenida = true;
            return promocionResultado;
        }

        protected virtual void ValidarAlAsociarPromocionInternal(DbAccionDeMarketingPromocion dbAccionPromocion, PtoVentaRegistroCliente customer)
        {
        }

        public void ValidarAlAsociarPromocion(PtoVentaRegistroCliente customer, bool esNuevo)
        {
            if (customer.EmpresaId == this.EmpresaId)
            {
                DateTime dateNow = DateTime.Now.Date;
                DateTime now = DateTime.Now;
                using (TransactionScope tScope = new TransactionScope())
                {
                    using (CrmContactoEntities ctx = new CrmContactoEntities())
                    {
                        List<int> IdsPromocion = new List<int>();
                        foreach (var factura in customer.Facturas)
                        {
                            if (!String.IsNullOrEmpty(factura.Factura))
                            {
                                if (factura.AccionDeMarketingId.HasValue)
                                {
                                    IdsPromocion.Add(factura.AccionDeMarketingId.Value);
                                }
                            }
                        }

                        // Obtengo las promociones que son de mi tipo
                        List<DbAccionDeMarketingPromocion> promocionesDeMiTipoList = ctx.DbAccionDeMarketingPromocions.Where(p => IdsPromocion.Contains(p.Id) && p.TipoImplementacion == Nombre && p.AccionDeMarketing.PlanDeMarketing.EmpresaId == customer.EmpresaId).ToList();

                        // Si hay algo q considerar
                        if (promocionesDeMiTipoList.Count > 0)
                        {
                            // Valido que el pack de promociones no esté en uso de distintas                            
                            // Cada id distinto tengo que verificar que no haya sido utilizado
                            List<DbAccionDeMarketingPromocion> promocionesDeMiTipoNoUtilizadasList = new List<DbAccionDeMarketingPromocion>();
                            foreach (var promoDeMiTipo in promocionesDeMiTipoList)
                            {
                                if (promoDeMiTipo.AccionDeMarketing.FechaDesde.Value > now || promoDeMiTipo.AccionDeMarketing.FechaHasta.Value < now)
                                {
                                    // la promoción está fuera de fecha
                                    throw new SvcBusinessException(string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoUSO.FueraFecha"], promoDeMiTipo.AccionDeMarketing.CodigoParaPDV));
                                }

                                if (promoDeMiTipo.AccionDeMarketingPromocionUsoes.Where(u => u.ContactoId == customer.Id).Count() > 0)
                                {
                                    // Excepcion ya ha sido utilizado
                                    throw new SvcBusinessException(string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoUSO.PromocionYaUtilizada"], promoDeMiTipo.AccionDeMarketing.CodigoParaPDV));
                                }

                                ValidarAlAsociarPromocionInternal(promoDeMiTipo, customer);

                                // Si no fue utilizado, lo utilizo y guardo la promoción
                                DbAccionDeMarketingPromocionUso dbPromoUso = new DbAccionDeMarketingPromocionUso();
                                dbPromoUso.ContactoId = customer.Id;
                                dbPromoUso.EmpresaId = customer.EmpresaId;
                                dbPromoUso.FechaUtilizacion = now;
                                dbPromoUso.PuntoDeVentaIdUtilizacion = customer.PuntoDeVentaId;
                                dbPromoUso.AuditFechaCreacion = now;
                                dbPromoUso.AuditUserNameCreacion = customer.UserName;

                                promoDeMiTipo.AccionDeMarketingPromocionUsoes.Add(dbPromoUso);

                                // Bitacora
                                List<DbContactoBitacora> bitacoraList = new List<DbContactoBitacora>();
                                var dbCustomer = ctx.DbContactoes.Where(c => c.EmpresaId == customer.EmpresaId && c.Id == customer.Id).Single();
                                AgregarBitacoraMensaje(bitacoraList, string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoUSO.PromocionUtilizada"], promoDeMiTipo.AccionDeMarketing.CodigoParaPDV), customer.UserName, dateNow);
                                bitacoraList.ForEach(b => { b.ContactoId = dbCustomer.Id; ctx.DbContactoBitacoras.AddObject(b); });

                                AsignarMensajeDeExito(customer, promoDeMiTipo);
                            }

                            ctx.SaveChanges();
                        }

                        tScope.Complete();
                    }
                }
            }
        }

        protected virtual void AsignarMensajeDeExito(PtoVentaRegistroCliente customer, DbAccionDeMarketingPromocion promocion)
        {
            if (customer.ServiceMessageOK == null)
                customer.ServiceMessageOK = string.Empty;

            customer.ServiceMessageOK += customer.ServiceMessageOK + string.Format(LocalizationProvider.Instance["Bo.Validacion.PromoUSO.PromocionUtilizada"], promocion.AccionDeMarketing.CodigoParaPDV);
        }

        public virtual bool FiltrarPromocionEnPdv(CrmContactoEntities ctxCrm, DbAccionDeMarketing accionesDeMarketing, CampaniasActivasSearch search)
        {
            bool esValida = false;
            if (search.ContactoId.HasValue)
            {
                if (accionesDeMarketing != null)
                {
                    DbContacto dbContacto = ctxCrm.DbContactoes.FilterLogicalRemoved().Where(c => c.Id == search.ContactoId.Value && c.EmpresaId == search.EmpresaId).SingleOrDefault();
                    if (dbContacto != null)
                    {
                        esValida = false;
                        // Si el contacto fue registrado antes del 6/7/2012
                        if (accionesDeMarketing.FechaDesde.HasValue)
                        {
                            if (dbContacto.AuditFechaCreacion.Date < accionesDeMarketing.FechaDesde.Value.Date)
                            {
                                // No uso la promocion
                                if (accionesDeMarketing.AccionDeMarketingPromocion.AccionDeMarketingPromocionUsoes.Where(u => u.ContactoId == search.ContactoId).Count() == 0)
                                {
                                    esValida = true;
                                }
                            }
                        }
                    }
                }
            }

            return !esValida;
        }

        private static void AgregarBitacoraMensaje(List<DbContactoBitacora> bitacoraList, string mensaje, string userName, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Mensaje;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = now;
            bitacoraList.Add(dbContactoBitacora);
        }

        public ParticipantesSearchResult GetParticipantes(ParticipantesSearch searchParam)
        {
            // Aplican: todos los inscriptos en el CRM antes de la fecha de inicio de la promoción.
            ParticipantesSearchResult result = new ParticipantesSearchResult();
            List<ParticipantePromocion> clientes = new List<ParticipantePromocion>();

            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                ctxCrm.CommandTimeout = 300;
                int totalDeResultados = 0;
                IQueryable<DbContacto> query = ctxCrm.DbContactoes.FilterLogicalRemoved();

                var dbPromocion = ctxCrm.DbAccionDeMarketingPromocions.Where(p => p.Id == searchParam.PromocionId).Single();

                DateTime? desde = dbPromocion.AccionDeMarketing.FechaDesde;
                DateTime? hasta = dbPromocion.AccionDeMarketing.FechaHasta;

                query = query.Where(c => c.EmpresaId == searchParam.EmpresaId);

                List<int> contactoIdList = new List<int>();
                if (searchParam.EmailList.Count > 0)
                {
                    contactoIdList = ctxCrm.DbContactoes.Where(c => searchParam.EmailList.Contains(c.Email)).Select(c => c.Id).ToList();
                    query = query.Where(c => contactoIdList.Contains(c.Id));
                }

                if (desde.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion < desde.Value);
                }

                if (searchParam.Desde.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion >= searchParam.Desde.Value);
                }

                if (searchParam.Hasta.HasValue)
                {
                    query = query.Where(c => c.AuditFechaCreacion <= searchParam.Hasta.Value);
                }

                // Hay dos tipos, los que se les envio email y los que no (por X motivo) pero no tenemos esa infor
                //if (searchParam.AccionMarketingPromocionSubConjuntoAplicacionId == (int)AccionMarketingPromocionSubConjuntoAplicacion.AplicacionSubconjunto)
                //{
                //    // Generaron cupón
                //    query = query.Where(c => c.AccionDeMarketingCupones.Count() > 0);
                //}

                totalDeResultados = query.Count();

                result.TotalDeResultados = totalDeResultados;

                if (searchParam.PageSize != 0)
                {
                    query = query.OrderByWithParam(searchParam.SortingField, searchParam.SortIsAsc).AsQueryable();
                    query = query.Skip(searchParam.PageSkip).Take(searchParam.PageSize);
                }

                List<DbContacto> dbContactoList = query.ToList();

                result.PageIndex = searchParam.PageSkip;
                result.PageSize = searchParam.PageSize;

                foreach (DbContacto dbContacto in dbContactoList)
                {
                    ParticipantePromocion registro = new ParticipantePromocion();
                    CrmContactoAdminService.LoadCustomerVeryBasicInfo(dbContacto, registro);
                    // No se usan cupones                   
                    clientes.Add(registro);
                }
            }

            result.Resultados = clientes;

            return result;
        }
    }
}
